/**
 * 
 */
package com.jintian.smart.kernel.common.expr.op.define;

import com.alibaba.fastjson.parser.ParserConfig;
import com.alibaba.fastjson.util.TypeUtils;
import com.jintian.smart.kernel.common.expr.datameta.BaseDataMeta;
import com.jintian.smart.kernel.common.expr.datameta.Constant;
import com.jintian.smart.kernel.common.expr.op.Operator;
import com.jintian.smart.kernel.core.expr.IllegalExpressionException;

import java.util.Collection;
import java.util.Comparator;

/**
 * 范围运算
 * 
 */
public class Op_BETWEEN extends Op_Base {
	public Op_BETWEEN() {
		super(Operator.BETWEEN);
	}

	public Constant execute(Constant[] args) throws IllegalExpressionException {
		Object[] params = this.getParameterValues(args);
		if (params[1] == null) {
			return new Constant(BaseDataMeta.DataType.DATATYPE_BOOLEAN, Boolean.FALSE);
		}
		return new Constant(BaseDataMeta.DataType.DATATYPE_BOOLEAN, between(params[0], params[1]));
	}

	@SuppressWarnings({ "rawtypes", "unchecked" })
	private boolean between(Object source, Object target) {
		if (source == null)
			return false;
		Object[] range = target.getClass().isArray() ? (Object[]) target
				: (target instanceof Collection) ? ((Collection) target).toArray(new Object[0]) : null;
		if (range == null) {
			// 如果操作数没有NULL型，且类型不同，抛异常（如果有校验，校验时就应该抛异常）
			throw new IllegalArgumentException(
					"操作符\"" + Operator.BETWEEN.getToken() + "\"第2个参数类型错误应为集合或数组，实际为" + target.getClass());
		}
		Object min = TypeUtils.cast(range[0], source.getClass(), ParserConfig.getGlobalInstance());
		Object max = TypeUtils.cast(range[1], source.getClass(), ParserConfig.getGlobalInstance());
		Comparator comparator = range.length > 2 ? (Comparator) range[2] : null;
		if (comparator == null && !(source instanceof Comparable)) {
			throw new IllegalArgumentException("操作符\"" + Operator.BETWEEN.getToken() + "\"参数类型错误");
		}
		if (comparator == null) {
			comparator = new NumberComparator();
		}
		if (min == null && max == null)
			return false;
		else if (min == null && max != null) {
			return comparator.compare(source, max) <= 0;
		} else if (min != null && max == null) {
			return comparator.compare(source, min) >= 0;
		} else if (min != null && max != null) {
			return comparator.compare(source, min) >= 0 && comparator.compare(source, max) <= 0;
		}
		return false;

	}

	public Constant verify(int opPositin, BaseDataMeta[] args) throws IllegalExpressionException {
		this.checkParameterCount(opPositin, args);

		BaseDataMeta second = args[0];

		if (BaseDataMeta.DataType.DATATYPE_LIST == second.getDataType()
				|| BaseDataMeta.DataType.DATATYPE_OBJECT == second.getDataType()) {
			return new Constant(BaseDataMeta.DataType.DATATYPE_BOOLEAN, Boolean.FALSE);

		} else {
			// 抛异常
			throw new IllegalExpressionException("操作符\"" + Operator.BETWEEN.getToken() + "\"参数类型错误",
					Operator.BETWEEN.getToken(), opPositin);
		}
	}

}
